package com.zb.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Assert;
import com.zb.entity.ZjCustomerWxAuthor;
import com.zb.exception.WxException;
import com.zb.http.HttpClientUtil;
import com.zb.redis.RedisUtil;
import com.zb.service.ZjCustomerWxAuthorService;
import com.zb.wx.WxCacheKeyConstant;
import com.zb.wx.WxHttpClientCodeHandler;
import com.zb.wx.WxPublicNoApiAuthorizeConstant;
import com.zb.wx.WxSecretKeyConstant;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;


/**
 * @Author WEN
 * @Date 2024/2/29 0029
 **/
@Service
public class WxHttpClientUtil {
    private static final Logger logger = LoggerFactory.getLogger(WxHttpClientUtil.class);
    private static WxHttpClientUtil wxHttpClientUtil;
    @Resource
    private ZjCustomerWxAuthorService customerWxAuthorService;

    @PostConstruct
    public void init() {
        wxHttpClientUtil = this;
    }


    /**
     * 获取微信票据
     * @return
     */
    public static String getComponentVerifyTicket() {
        return (String) RedisUtil.getByKey(WxCacheKeyConstant.WX_COMPONENT_VERIFY_TICKET);
    }

    /**
     * 获取微信令牌
     * @return
     */
    public static String getComponentAccessToken() throws WxException {
        if (RedisUtil.hasKey(WxCacheKeyConstant.WX_COMPONENT_ACCESS_TOKEN)) {
            return (String) RedisUtil.getByKey(WxCacheKeyConstant.WX_COMPONENT_ACCESS_TOKEN);
        }
        // 获取票据
        String componentVerifyTicket = getComponentVerifyTicket();
        Assert.notNull(componentVerifyTicket, "请求微信授权票据已过期，请稍后再重试");

        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("component_appid", WxSecretKeyConstant.APP_ID);
        paramMap.put("component_appsecret",WxSecretKeyConstant.APP_SECRET);
        paramMap.put("component_verify_ticket", componentVerifyTicket);
        String body = HttpClientUtil.post(WxPublicNoApiAuthorizeConstant.AUTHOR_OMPONENT_TOKEN_API, paramMap);
        // 检查返回的结果
        WxHttpClientCodeHandler.checkWxHttpClientResultCode(body);

        JSONObject bodyJson = JSON.parseObject(body, JSONObject.class);
        String componentAccessToken = bodyJson.getString("component_access_token");
        // 提前20分钟过期
        long expiresIn = bodyJson.getLong("expires_in") - 1200;
        RedisUtil.setCache(WxCacheKeyConstant.WX_COMPONENT_ACCESS_TOKEN, componentAccessToken, expiresIn);
        return componentAccessToken;
    }

    /**
     * 获取预授权码
     * @return
     */
    public static String getPreAuthCode() throws WxException {
        if (RedisUtil.hasKey(WxCacheKeyConstant.WX_PRE_AUTH_CODE)) {
            return (String) RedisUtil.getByKey(WxCacheKeyConstant.WX_PRE_AUTH_CODE);
        }
        // 获取第三方授权令牌
        String componentAccessToken = getComponentAccessToken();
        // 获取预授权码
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("component_appid", WxSecretKeyConstant.APP_ID);
        String body = HttpClientUtil.post(WxPublicNoApiAuthorizeConstant.AUTHOR_CREATE_PREAUTHCODE_API.replaceAll("COMPONENT_ACCESS_TOKEN", componentAccessToken), paramMap);
        // 检查返回的结果
        WxHttpClientCodeHandler.checkWxHttpClientResultCode(body);

        JSONObject bodyJson = JSON.parseObject(body, JSONObject.class);
        String preAuthCode = bodyJson.getString("pre_auth_code");
        long expiresIn = bodyJson.getLong("expires_in") - 1200;
        RedisUtil.setCache(WxCacheKeyConstant.WX_PRE_AUTH_CODE, preAuthCode, expiresIn);
        return preAuthCode;
    }

    /**
     * 根据授权码获取授权信息
     * @param authCode 授权码, 会在授权成功时返回给第三方平台
     * @return 返回结果示例：{
     *   "authorization_info": {
     *     "authorizer_appid": "wxf8b4f85f3a794e77",
     *     "authorizer_access_token": "QXjUqNqfYVH0yBE1iI_7vuN_9gQbpjfK7hYwJ3P7xOa88a89-Aga5x1NMYJyB8G2yKt1KCl0nPC3W9GJzw0Zzq_dBxc8pxIGUNi_bFes0qM",
     *     "expires_in": 7200,
     *     "authorizer_refresh_token": "dTo-YCXPL4llX-u1W1pPpnp8Hgm4wpJtlR6iV0doKdY",
     *     "func_info": [
     *       {
     *         "funcscope_category": {
     *           "id": 1
     *         }
     *       },
     *       {
     *         "funcscope_category": {
     *           "id": 2
     *         }
     *       },
     *       {
     *         "funcscope_category": {
     *           "id": 3
     *         }
     *       }
     *     ]
     *   }
     * }
     * @throws WxException
     */
   public static JSONObject getQueryAuthCode(String authCode) throws WxException {
       // 获取第三方授权令牌
       String componentAccessToken = getComponentAccessToken();

       Map<String, Object> paramMap = new HashMap<>();
       paramMap.put("component_appid", WxSecretKeyConstant.APP_ID);
       paramMap.put("authorization_code", authCode);

       String url = WxPublicNoApiAuthorizeConstant.GET_QUERY_AUTH_CODE_API.replaceAll("COMPONENT_ACCESS_TOKEN", componentAccessToken);
       String body = HttpClientUtil.post(url, paramMap);
       // 检查返回的结果
       WxHttpClientCodeHandler.checkWxHttpClientResultCode(body);
       return JSON.parseObject(body, JSONObject.class);
   }

    /**
     * 获取授权账号调用令牌AuthorizerAccessToken,该方法包含了[刷新]授权账号调用令牌AuthorizerAccessToken
     * @param custAccId 商家ID
     * @return
     * @throws WxException
     */
    public static String getAuthorizerAccessToken(Long custAccId) throws WxException {
        if (RedisUtil.hasKey(WxCacheKeyConstant.WX_AUTHORIZER_ACCESS_TOKEN + custAccId)) {
            return (String) RedisUtil.getByKey(WxCacheKeyConstant.WX_AUTHORIZER_ACCESS_TOKEN + custAccId);
        }
        // 获取第三方授权令牌
        String componentAccessToken = getComponentAccessToken();
        ZjCustomerWxAuthor wxAuthor = wxHttpClientUtil.customerWxAuthorService.getAuthorizerById(custAccId);

        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("component_appid", WxSecretKeyConstant.APP_ID);
        paramMap.put("authorizer_appid", wxAuthor.getAuthorizerAppid());
        paramMap.put("authorizer_refresh_token", wxAuthor.getAuthorizerRefreshToken());
        String url = WxPublicNoApiAuthorizeConstant.GET_AUTHORIZER_TOKEN_API.replaceAll("COMPONENT_ACCESS_TOKEN", componentAccessToken);
        String body = HttpClientUtil.post(url, paramMap);
        // 检查返回的结果
        WxHttpClientCodeHandler.checkWxHttpClientResultCode(body);
        JSONObject objData = JSON.parseObject(body, JSONObject.class);
        String authorizerAccessToken = objData.getString("authorizer_access_token");
        Long authorizerAccessTokenExpiresIn = objData.getLong("expires_in");
        // 缓存令牌
        setCacheAuthorizerAccessToken(custAccId, authorizerAccessToken, authorizerAccessTokenExpiresIn);
        return authorizerAccessToken;
    }

    /**
     * 缓存授权账号调用令牌AuthorizerAccessToken
     * @param custAccId 商家ID
     * @param authorizerAccessToken 授权账号调用令牌
     * @param authorizerAccessTokenExpiresIn 过期时间
     */
    public static void setCacheAuthorizerAccessToken(Long custAccId, String authorizerAccessToken, Long authorizerAccessTokenExpiresIn) {
        // 提前20分钟过期
        authorizerAccessTokenExpiresIn = authorizerAccessTokenExpiresIn -1200;
        RedisUtil.setCache(WxCacheKeyConstant.WX_AUTHORIZER_ACCESS_TOKEN + custAccId, authorizerAccessToken, authorizerAccessTokenExpiresIn);
    }

    /**
     * 获取公众号或小程序所绑定的开放平台账号的 openAppId
     * @param custAccId 商家ID
     * @return
     * @throws WxException
     */
    public static String getOpenAppid(Long custAccId) throws WxException {
        String authorizerAccessToken = getAuthorizerAccessToken(custAccId);

        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("appid", WxSecretKeyConstant.APP_ID);

        String url = WxPublicNoApiAuthorizeConstant.GET_PUBLIC_NO_BIND_THIRD_API.replaceAll("ACCESS_TOKEN", authorizerAccessToken);
        String body = HttpClientUtil.post(url);
        // 检查返回的结果
        WxHttpClientCodeHandler.checkWxHttpClientResultCode(body);
        JSONObject bodyObj = JSON.parseObject(body, JSONObject.class);
        return bodyObj.getString("open_appid");
    }

    /**
     * 创建开放平台账号与公众号授权绑定
     * @param authorizerAccessToken
     * @param authorizerAppid
     * @return 所创建的开放平台账号的 appid
     * @throws WxException
     */
    public static String createOpenAccountBindAuthorPubicNo(String authorizerAccessToken, String authorizerAppid) throws WxException {
        String openAppId = null;
        try {
            String url = WxPublicNoApiAuthorizeConstant.CREATE_OPEN_ACCOUNT_BIND_AUTHOR_PUBLIC_NO_API.replaceAll("ACCESS_TOKEN", authorizerAccessToken);

            Map<String, Object> paramMap = new HashMap<>();
            paramMap.put("appid", authorizerAppid);
            String body = HttpClientUtil.post(url, paramMap);
            JSONObject bodyObj = JSON.parseObject(body, JSONObject.class);
            // 检查返回的结果
            WxHttpClientCodeHandler.checkWxHttpClientResultCode(body);
            openAppId = bodyObj.getString("open_appid");
        }catch (Exception e) {
            logger.info("创建开放平台账号与公众号授权绑定异常：{}", e);
            e.printStackTrace();
        }
        return openAppId;
    }

    /**
     * 公众号绑定授权第三方平台
     * @param authorizerAccessToken
     * @param authorizerAppid
     * @throws WxException
     */
    public static void publicNoBindAuthorThird(String authorizerAccessToken, String authorizerAppid) throws WxException {
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("open_appid", WxSecretKeyConstant.APP_ID);
        paramMap.put("appid", authorizerAppid);

        String url = WxPublicNoApiAuthorizeConstant.PUBLIC_NO_BIND_AUTHOR_THIRD_API.replaceAll("ACCESS_TOKEN", authorizerAccessToken);
        String body = HttpClientUtil.post(url, paramMap);
        logger.info("公众号绑定授权第三方平台结果：{}", body);
        // 检查返回的结果
        WxHttpClientCodeHandler.checkWxHttpClientResultCode(body);
    }

    /**
     * 解除公众号绑定第三方平台的授权
     * @param custAccId 商家ID
     * @param openAppid
     * @param authorizerAppid
     */
    public static void publicNoUnbindAuthorThird(Long custAccId, String openAppid, String authorizerAppid) {
        try {
            String authorizerAccessToken = getAuthorizerAccessToken(custAccId);

            Map<String, Object> paramMap = new HashMap<>();
            paramMap.put("open_appid", openAppid);
            paramMap.put("appid", authorizerAppid);

            String url = WxPublicNoApiAuthorizeConstant.PUBLIC_NO_UNBIND_AUTHOR_THIRD_API.replaceAll("ACCESS_TOKEN", authorizerAccessToken);
            String body = HttpClientUtil.post(url, paramMap);
            // 检查返回的结果
            WxHttpClientCodeHandler.checkWxHttpClientResultCode(body);
        }catch (Exception e) {
            logger.error("解除公众号绑定第三方平台的授权异常：{}", e);
            e.printStackTrace();
        }
    }

}
